import threading
import queue
import time
from datetime import datetime
from backend.database import db
from backend.models.task import Task
from backend.models.device import Device
from backend.services.device_manager.device_manager import DeviceManager
import logging

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger('task_scheduler')

class TaskScheduler:
    _instance = None
    _lock = threading.Lock()
    
    def __new__(cls):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super(TaskScheduler, cls).__new__(cls)
                cls._instance.task_queue = queue.PriorityQueue()
                cls._instance.running = False
                cls._instance.worker_threads = []
                cls._instance.max_workers = 5  # 最大工作线程数
                cls._instance.device_manager = DeviceManager()
        return cls._instance
    
    def start(self):
        """启动任务调度器"""
        if not self.running:
            self.running = True
            # 启动工作线程
            for i in range(self.max_workers):
                thread = threading.Thread(target=self._worker, args=(i,), daemon=True)
                self.worker_threads.append(thread)
                thread.start()
            logger.info(f"任务调度器已启动，工作线程数: {self.max_workers}")
    
    def stop(self):
        """停止任务调度器"""
        if self.running:
            self.running = False
            # 等待所有工作线程结束
            for thread in self.worker_threads:
                if thread.is_alive():
                    thread.join(timeout=3)
            self.worker_threads.clear()
            logger.info("任务调度器已停止")
    
    def _worker(self, worker_id):
        """工作线程函数"""
        logger.info(f"工作线程 {worker_id} 已启动")
        while self.running:
            try:
                # 从队列中获取任务，设置超时时间以便定期检查running状态
                priority, task = self.task_queue.get(timeout=1)
                logger.info(f"工作线程 {worker_id} 获取任务: {task.name} (优先级: {priority})")
                
                # 执行任务
                self._execute_task(task)
                
                # 标记任务完成
                self.task_queue.task_done()
            except queue.Empty:
                continue  # 队列为空，继续循环
            except Exception as e:
                logger.error(f"工作线程 {worker_id} 发生错误: {str(e)}")
        logger.info(f"工作线程 {worker_id} 已停止")
    
    def add_task(self, task):
        """添加任务到队列"""
        try:
            # 确保任务状态为等待中
            task.status = '等待中'
            db.session.commit()
            
            # 将任务添加到优先级队列
            self.task_queue.put((task.priority, task))
            logger.info(f"任务已添加到队列: {task.name} (ID: {task.id})")
            return True
        except Exception as e:
            db.session.rollback()
            logger.error(f"添加任务到队列时发生错误: {str(e)}")
            return False
    
    def _execute_task(self, task):
        """执行任务"""
        try:
            # 更新任务状态为运行中
            task.status = '运行中'
            task.start_time = datetime.utcnow()
            db.session.commit()
            logger.info(f"开始执行任务: {task.name} (ID: {task.id})")
            
            # 分配设备
            device = self.device_manager.allocate_device()
            if not device:
                logger.warning(f"任务 {task.name} (ID: {task.id}) 无法获取设备，重新放入队列")
                # 更新任务状态为等待中
                task.status = '等待中'
                db.session.commit()
                # 重新添加到队列
                self.task_queue.put((task.priority, task))
                return
            
            # 关联设备和任务
            device.current_task_id = task.id
            db.session.commit()
            
            try:
                # 执行脚本
                result = self._run_script_on_device(device, task)
                
                # 更新任务状态
                task.status = '已完成' if result['success'] else '失败'
                logger.info(f"任务执行{'成功' if result['success'] else '失败'}: {task.name} (ID: {task.id})")
            finally:
                # 释放设备
                self.device_manager.release_device(device.device_id)
                device.current_task_id = None
                
                # 更新任务结束时间
                task.end_time = datetime.utcnow()
                db.session.commit()
        except Exception as e:
            logger.error(f"执行任务时发生错误: {str(e)}")
            # 更新任务状态为失败
            try:
                task.status = '失败'
                task.end_time = datetime.utcnow()
                db.session.commit()
            except:
                pass
    
    def _run_script_on_device(self, device, task):
        """在设备上运行脚本"""
        try:
            # 获取脚本内容
            script_content = task.script.content
            script_language = task.script.language
            
            # 根据脚本语言执行不同的命令
            if script_language.lower() == 'python':
                # 这里可以实现Python脚本的执行逻辑
                # 例如将脚本推送到设备并执行
                result = {'success': True, 'stdout': 'Python script execution placeholder'}
            elif script_language.lower() == 'shell':
                # 执行shell命令
                result = self.device_manager.execute_command(device.device_id, script_content)
            else:
                # 其他语言的处理逻辑
                result = {'success': True, 'stdout': f'{script_language} script execution placeholder'}
            
            # 记录执行结果
            self._log_task_result(task.id, result)
            
            return result
        except Exception as e:
            logger.error(f"运行脚本时发生错误: {str(e)}")
            return {'success': False, 'stderr': str(e)}
    
    def _log_task_result(self, task_id, result):
        """记录任务执行结果"""
        # 这里可以实现日志记录逻辑
        # 例如将结果保存到数据库或文件系统
        logger.info(f"任务 {task_id} 执行结果: {result}")
    
    def create_task(self, name, description, script_id, priority=1, created_by='system'):
        """创建新任务"""
        try:
            new_task = Task(
                name=name,
                description=description,
                script_id=script_id,
                priority=priority,
                created_by=created_by
            )
            db.session.add(new_task)
            db.session.commit()
            
            # 将任务添加到队列
            self.add_task(new_task)
            
            logger.info(f"任务已创建: {name} (ID: {new_task.id})")
            return new_task
        except Exception as e:
            db.session.rollback()
            logger.error(f"创建任务时发生错误: {str(e)}")
            return None
    
    def get_task_by_id(self, task_id):
        """通过ID获取任务"""
        try:
            return Task.query.get(task_id)
        except Exception as e:
            logger.error(f"获取任务时发生错误: {str(e)}")
            return None
    
    def get_all_tasks(self):
        """获取所有任务"""
        try:
            return Task.query.all()
        except Exception as e:
            logger.error(f"获取任务列表时发生错误: {str(e)}")
            return []
    
    def get_tasks_by_status(self, status):
        """通过状态获取任务"""
        try:
            return Task.query.filter_by(status=status).all()
        except Exception as e:
            logger.error(f"获取任务列表时发生错误: {str(e)}")
            return []
    
    def cancel_task(self, task_id):
        """取消任务"""
        try:
            task = Task.query.get(task_id)
            if task and task.status == '等待中':
                # 这里需要实现从队列中移除任务的逻辑
                # 由于PriorityQueue没有直接的移除方法，这里只是更新数据库中的状态
                task.status = '已取消'
                db.session.commit()
                logger.info(f"任务已取消: {task.name} (ID: {task.id})")
                return True
            logger.warning(f"无法取消任务: {task_id}，任务状态: {task.status if task else '不存在'}")
            return False
        except Exception as e:
            db.session.rollback()
            logger.error(f"取消任务时发生错误: {str(e)}")
            return False